================================================================================
STOCKFISH CHESS BOT API - COMPLETE REFERENCE
================================================================================

BASE URL: https://stockfishapi.caprover.al-arcade.com

================================================================================
ENDPOINTS
================================================================================

--------------------------------------------------------------------------------
1. GET MOVE FROM BOT
--------------------------------------------------------------------------------

POST /api/chess/move

Description:
  Get a chess move from a specific bot personality. The bot will play according
  to its configured skill level, depth, contempt, and blunder probability.
  Response includes simulated human-like think time.

Headers:
  Content-Type: application/json

Request Body:
  {
    "fen": "string (required) - FEN notation of the current board position",
    "bot_id": "string (required) - ID of the bot to play against",
    "time_limit_ms": 0  (optional, int) - time limit in ms. If 0 or omitted, uses depth-based search
  }

Response (200 OK):
  {
    "best_move": "e2e4",         // UCI move notation (from-square + to-square, e.g. e2e4, g1f3, e7e8q for promotion)
    "evaluation": 0.35,          // centipawn evaluation / 100. Positive = white advantage. 999.0 = white mates, -999.0 = black mates
    "depth": 10,                 // search depth reached
    "nodes": 125000,             // nodes searched
    "think_time_ms": 1500,       // total time including artificial delay (simulates human thinking)
    "pv": "e2e4 e7e5 g1f3"      // principal variation (best line), space-separated UCI moves
  }

Errors:
  400: {"error": "invalid request body"}
  400: {"error": "fen is required"}
  400: {"error": "bot_id is required"}
  404: {"error": "bot not found"}
  500: {"error": "engine error: ..."}

Example:
  curl -X POST https://stockfishapi.caprover.al-arcade.com/api/chess/move \
    -H "Content-Type: application/json" \
    -d '{"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "bot_id": "nour"}'

--------------------------------------------------------------------------------
2. ANALYZE POSITION
--------------------------------------------------------------------------------

POST /api/chess/analyze

Description:
  Deep multi-line analysis of a position at full Stockfish strength (skill 20).
  Returns multiple candidate moves ranked by evaluation.

Headers:
  Content-Type: application/json

Request Body:
  {
    "fen": "string (required) - FEN notation of the position to analyze",
    "depth": 18,    (optional, int 1-30, default 18) - search depth
    "lines": 3      (optional, int 1-5, default 3) - number of candidate moves to return
  }

Response (200 OK):
  {
    "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1",
    "depth": 18,
    "lines": [
      {
        "rank": 1,
        "move": "e7e5",              // best move in UCI notation
        "evaluation": -0.25,         // eval from engine perspective (positive = side to move is better)
        "depth": 18,
        "pv": "e7e5 g1f3 b8c6 ..."  // full principal variation
      },
      {
        "rank": 2,
        "move": "c7c5",
        "evaluation": -0.15,
        "depth": 18,
        "pv": "c7c5 g1f3 d7d6 ..."
      }
    ]
  }

Errors:
  400: {"error": "invalid request body"}
  400: {"error": "fen is required"}
  500: {"error": "engine error: ..."}

Timeout: 30 seconds max per analysis request.

Example:
  curl -X POST https://stockfishapi.caprover.al-arcade.com/api/chess/analyze \
    -H "Content-Type: application/json" \
    -d '{"fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1", "depth": 20, "lines": 3}'

--------------------------------------------------------------------------------
3. LIST BOTS
--------------------------------------------------------------------------------

GET /api/chess/bots

Description:
  Returns all available bot personalities sorted by difficulty (easiest first).

Response (200 OK):
  {
    "bots": [
      {
        "id": "amina",
        "name": "Amina",
        "name_ar": "أمينة المبتدئة",
        "style": "beginner",
        "style_ar": "مبتدئة",
        "bio": "Just learning chess! Makes mistakes but tries her best.",
        "bio_ar": "لسه بتتعلم شطرنج! بتغلط كتير بس بتحاول.",
        "elo_min": 400,
        "elo_max": 600,
        "skill_level": 1,
        "depth": 3,
        "contempt": 0,
        "blunder_chance": 0.30,
        "think_time_min_ms": 500,
        "think_time_max_ms": 2000,
        "opening_book": [],
        "avatar_id": "bot-amina",
        "portrait_url": "/portraits/amina.png"
      },
      ...
    ]
  }

Example:
  curl https://stockfishapi.caprover.al-arcade.com/api/chess/bots

--------------------------------------------------------------------------------
4. POOL STATS
--------------------------------------------------------------------------------

GET /api/chess/stats

Description:
  Returns the current Stockfish process pool status.

Response (200 OK):
  {
    "pool_alive": 6,    // number of Stockfish processes currently running
    "pool_idle": 4      // number of those processes currently idle (available)
  }

Example:
  curl https://stockfishapi.caprover.al-arcade.com/api/chess/stats

--------------------------------------------------------------------------------
5. HEALTH CHECK
--------------------------------------------------------------------------------

GET /health

Description:
  Verifies the engine is operational by running a depth-1 search on the
  starting position. Used by CapRover/Docker health checks.

Response (200 OK):
  {
    "status": "healthy",
    "engine": "stockfish-18",
    "pool_alive": 6,
    "pool_idle": 4
  }

Response (503 Service Unavailable):
  {
    "status": "unhealthy",
    "error": "acquire process: context deadline exceeded"
  }

Example:
  curl https://stockfishapi.caprover.al-arcade.com/health


================================================================================
AVAILABLE BOTS (sorted by difficulty)
================================================================================

ID            | Name            | Arabic Name      | Style        | Style (AR)  | ELO       | Skill | Depth | Blunder% | Think Time (ms) | Portrait
--------------|-----------------|------------------|--------------|-------------|-----------|-------|-------|----------|-----------------|------------------
amina         | Amina           | أمينة المبتدئة   | beginner     | مبتدئة      | 400-600   | 1     | 3     | 30%      | 500-2000        | /portraits/amina.png
tarek         | Tarek           | طارق المتحفظ     | defensive    | دفاعي       | 800-1000  | 5     | 6     | 15%      | 1000-3000       | /portraits/tarek.png
nour          | Nour            | نور المهاجمة     | aggressive   | هجومية      | 1000-1200 | 8     | 10    | 8%       | 800-3000        | /portraits/nour.png
omar          | Omar            | عمر الاستراتيجي  | positional   | استراتيجي   | 1200-1400 | 11    | 12    | 4%       | 1500-4000       | /portraits/omar.png
layla         | Layla           | ليلى المبدعة     | creative     | إبداعية     | 1400-1600 | 14    | 14    | 2%       | 1000-5000       | /portraits/layla.png
ziad          | Ziad            | زياد الصلب       | solid        | صلب         | 1600-1800 | 17    | 16    | 1%       | 2000-6000       | /portraits/ziad.png
grandmaster   | Grandmaster Bot | الجراند ماستر    | near_perfect | شبه مثالي   | 2000-2200 | 20    | 20    | 0%       | 3000-8000       | /portraits/grandmaster.png


================================================================================
BOT BEHAVIOR DETAILS
================================================================================

BLUNDER MECHANISM:
  Each move request, the bot rolls against its blunder_chance probability.
  If it "blunders", the engine searches at depth=1 with skill_level=0,
  producing a weak/random move. Otherwise it plays at its configured strength.

THINK TIME SIMULATION:
  After the engine returns a move, the API adds artificial delay to simulate
  human-like thinking. The delay is random between think_time_min and think_time_max.
  Total response time = engine_time + artificial_delay.
  If the client disconnects (context cancelled), the delay is aborted.

CONTEMPT:
  Positive contempt = bot plays more aggressively, avoids draws.
  Negative contempt = bot is happy to draw, plays defensively.
  Range: -100 to 100.

SKILL LEVEL:
  Stockfish's internal skill parameter (0-20).
  0 = weakest, introduces random errors.
  20 = full strength, no artificial weakening.

OPENING BOOKS (metadata only, not enforced by engine):
  Listed per bot for frontend display. The engine does not use opening books;
  it calculates from the given FEN position directly.

AVATAR IDs:
  Each bot has an avatar_id field for frontend use (e.g. "bot-amina", "bot-nour").
  Map these to your avatar image assets.

PORTRAITS:
  Each bot has a portrait_url field pointing to a 512x512 pixel image.
  Portraits are served publicly at: https://stockfishapi.caprover.al-arcade.com/portraits/{bot_id}.png
  Supported formats: PNG, JPG, WebP.
  Upload via admin panel: /admin/bots/edit/{id} -> Portrait upload form.
  Recommended dimensions: 512x512 pixels (square).
  These are character portraits/avatars for display in the chess UI.

STYLE LABELS (Arabic):
  Each bot has a "style_ar" field with the Arabic translation of its play style.
  Use this for bilingual (EN/AR) UI display.
  Examples: "مبتدئة" (beginner), "دفاعي" (defensive), "هجومية" (aggressive),
            "استراتيجي" (positional), "إبداعية" (creative), "صلب" (solid),
            "شبه مثالي" (near_perfect).


================================================================================
MOVE NOTATION
================================================================================

All moves use UCI (Universal Chess Interface) long algebraic notation:
  - Normal move: source_square + destination_square (e.g. "e2e4", "g1f3")
  - Pawn promotion: source + destination + piece_letter (e.g. "e7e8q" for queen promotion)
  - Castling: king's start + king's end (e.g. "e1g1" for white kingside, "e1c1" for queenside)
  - En passant: normal pawn capture notation (e.g. "e5d6")

Piece letters for promotion: q=queen, r=rook, b=bishop, n=knight


================================================================================
FEN (Forsyth-Edwards Notation) FORMAT
================================================================================

A FEN string describes a complete board position in a single line:

  "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
   |         |         |      |    |  |
   |         |         |      |    |  +-- fullmove number
   |         |         |      |    +----- halfmove clock (50-move rule)
   |         |         |      +---------- en passant target square ("-" if none)
   |         |         +----------------- castling availability (KQkq or "-")
   |         +--------------------------- active color: "w" or "b"
   +------------------------------------- piece placement (rank 8 to rank 1, "/" separated)

Piece letters: K=king, Q=queen, R=rook, B=bishop, N=knight, P=pawn
  Uppercase = white, lowercase = black
  Numbers = consecutive empty squares

Starting position FEN:
  rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1


================================================================================
EVALUATION VALUES
================================================================================

The "evaluation" field in responses:
  - Measured in pawns (centipawns / 100)
  - Positive = white advantage
  - Negative = black advantage
  - +0.50 means white is half a pawn ahead
  - +999.0 = white has forced checkmate
  - -999.0 = black has forced checkmate
  - Values near 0.0 = roughly equal position


================================================================================
RATE LIMITING
================================================================================

  - 60 requests per minute per IP address
  - Applies to all endpoints
  - X-Forwarded-For header is respected (for reverse proxy setups)
  - When exceeded: 429 Too Many Requests {"error": "rate limit exceeded"}


================================================================================
CORS
================================================================================

  - Access-Control-Allow-Origin: * (all origins allowed)
  - Allowed Methods: GET, POST, OPTIONS
  - Allowed Headers: Content-Type, Authorization, apikey
  - Preflight cache: 86400 seconds (24 hours)


================================================================================
MANAGEMENT API (Full Control)
================================================================================

Base: https://stockfishapi.caprover.al-arcade.com/api/manage

Authentication:
  All /api/manage/* endpoints require an API key via header:
    X-API-Key: sk-alarc-stockfish-mgmt-2024
  OR:
    Authorization: Bearer sk-alarc-stockfish-mgmt-2024

Rate Limiting: None on management endpoints (auth-gated).

--------------------------------------------------------------------------------
SYSTEM INFO
--------------------------------------------------------------------------------

GET /api/manage/info

  Returns full system overview + all available endpoint list.

  Response:
  {
    "engine": "stockfish-18",
    "version": "1.0.0",
    "bot_count": 7,
    "pool": { "alive": 6, "idle": 4, "max_size": 12, "idle_timeout": 300 },
    "settings": { "port": "80", "stockfish_path": "/usr/local/bin/stockfish" },
    "endpoints": { ... all endpoints listed ... }
  }

--------------------------------------------------------------------------------
BOT CRUD
--------------------------------------------------------------------------------

GET /api/manage/bots
  List all bots with count.

GET /api/manage/bots/{id}
  Get a single bot by ID.

POST /api/manage/bots
  Create a new bot. Send full bot JSON in body.
  Required: id, name, style
  Returns 201 on success, 409 if ID already exists.

  Body:
  {
    "id": "yasmin",
    "name": "Yasmin",
    "name_ar": "ياسمين",
    "style": "tricky",
    "style_ar": "ماكرة",
    "bio": "Sets traps and waits for you to fall in.",
    "bio_ar": "بتحط فخاخ وبتستنى تقع فيها.",
    "elo_min": 1100,
    "elo_max": 1300,
    "skill_level": 9,
    "depth": 11,
    "contempt": 20,
    "blunder_chance": 0.06,
    "think_time_min_ms": 1000,
    "think_time_max_ms": 3500,
    "opening_book": ["sicilian", "french"],
    "avatar_id": "bot-yasmin",
    "portrait_url": "/portraits/yasmin.png"
  }

PATCH /api/manage/bots/{id}
  Partial update. Only send fields you want to change.
  Body: { "skill_level": 12, "blunder_chance": 0.05, "style_ar": "ذكية" }

PUT /api/manage/bots/{id}
  Full replace. Overwrites entire bot with new data.
  Body: same as POST but ID comes from URL.

DELETE /api/manage/bots/{id}
  Delete a bot and its portrait files.

--------------------------------------------------------------------------------
BULK OPERATIONS
--------------------------------------------------------------------------------

POST /api/manage/bots/bulk
  Create multiple bots at once.
  Body: [ {bot1}, {bot2}, ... ]
  Response: { "created": ["id1","id2"], "skipped": ["id3 (already exists)"] }

DELETE /api/manage/bots/bulk
  Delete multiple bots at once.
  Body: { "ids": ["amina", "tarek"] }
  Response: { "deleted": ["amina","tarek"], "not_found": [] }

GET /api/manage/bots/export
  Download all bots as JSON file (Content-Disposition: attachment).

POST /api/manage/bots/import?overwrite=true
  Import bots from JSON array. With overwrite=true, existing bots are replaced.
  Body: [ {bot1}, {bot2}, ... ]
  Response: { "imported": ["id1"], "skipped": ["id2 (exists)"], "total": 8 }

--------------------------------------------------------------------------------
PORTRAIT MANAGEMENT
--------------------------------------------------------------------------------

POST /api/manage/bots/{id}/portrait
  Upload a portrait image (512x512 px).
  Content-Type: multipart/form-data
  Field name: "portrait"
  Accepted: .png, .jpg, .jpeg, .webp (max 10MB)

  curl example:
    curl -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/bots/amina/portrait \
      -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
      -F "portrait=@amina_512x512.png"

  Response: { "status": "uploaded", "bot_id": "amina", "portrait_url": "/portraits/amina.png", "size_bytes": 245000 }

DELETE /api/manage/bots/{id}/portrait
  Delete all portrait files for a bot.
  Response: { "status": "deleted", "bot_id": "amina" }

Portraits are served publicly (no auth):
  GET https://stockfishapi.caprover.al-arcade.com/portraits/{bot_id}.png

--------------------------------------------------------------------------------
ENGINE / POOL
--------------------------------------------------------------------------------

GET /api/manage/pool
  Full pool stats with utilization percentage.
  Response:
  {
    "pool_alive": 6,
    "pool_idle": 4,
    "pool_max_size": 12,
    "pool_utilization": "16.7%",
    "idle_timeout_sec": 300
  }

POST /api/manage/test-move
  Test the engine directly. Supports raw mode (custom params) or bot mode.

  Bot mode:
  { "fen": "...", "bot_id": "nour" }

  Raw mode (bypass bot config, use custom engine params):
  {
    "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1",
    "raw_mode": true,
    "depth": 25,
    "skill_level": 20,
    "contempt": 0,
    "time_limit_ms": 5000,
    "multi_pv": 3
  }

  Response:
  {
    "best_move": "e7e5",
    "evaluation": -0.12,
    "depth": 25,
    "nodes": 5000000,
    "pv": "e7e5 g1f3 b8c6",
    "engine_time_ms": 3200,
    "request": { "fen": "...", "depth": 25, "skill_level": 20, "contempt": 0, "multi_pv": 3 }
  }

POST /api/manage/analyze
  Deep analysis (up to depth 40, up to 10 lines).
  { "fen": "...", "depth": 30, "lines": 5 }
  Response: { "fen": "...", "depth": 30, "lines": [...], "engine_time_ms": 12000 }

--------------------------------------------------------------------------------
SETTINGS
--------------------------------------------------------------------------------

GET /api/manage/settings
  { "port": "80", "pool_size": 12, "idle_timeout_sec": 300, "stockfish_path": "/usr/local/bin/stockfish" }

PATCH /api/manage/settings
  Update settings (partial). Some require restart.
  Body: { "pool_size": 16, "idle_timeout_sec": 600 }
  Response: { "status": "updated", "settings": {...}, "note": "some changes require restart" }

--------------------------------------------------------------------------------
LOGS
--------------------------------------------------------------------------------

GET /api/manage/logs?limit=50
  Get recent request logs (max 100).
  Response:
  {
    "logs": [
      { "Timestamp": "2024-01-15 14:30:22", "Method": "POST", "Path": "/api/chess/move", "Status": 200, "Duration": "45ms", "IP": "1.2.3.4" },
      ...
    ],
    "count": 50
  }


================================================================================
MANAGEMENT API - QUICK REFERENCE (curl examples)
================================================================================

# Auth header (use in all requests)
AUTH="-H 'X-API-Key: sk-alarc-stockfish-mgmt-2024'"

# System info
curl -s https://stockfishapi.caprover.al-arcade.com/api/manage/info \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# List bots
curl -s https://stockfishapi.caprover.al-arcade.com/api/manage/bots \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# Get single bot
curl -s https://stockfishapi.caprover.al-arcade.com/api/manage/bots/nour \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# Create bot
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/bots \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"id":"yasmin","name":"Yasmin","name_ar":"ياسمين","style":"tricky","style_ar":"ماكرة","skill_level":9,"depth":11,"contempt":20,"blunder_chance":0.06,"think_time_min_ms":1000,"think_time_max_ms":3500,"elo_min":1100,"elo_max":1300}' | jq .

# Update bot (partial)
curl -s -X PATCH https://stockfishapi.caprover.al-arcade.com/api/manage/bots/amina \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"skill_level":2,"blunder_chance":0.25}' | jq .

# Replace bot (full)
curl -s -X PUT https://stockfishapi.caprover.al-arcade.com/api/manage/bots/amina \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"name":"Amina","name_ar":"أمينة","style":"beginner","style_ar":"مبتدئة","skill_level":1,"depth":3}' | jq .

# Delete bot
curl -s -X DELETE https://stockfishapi.caprover.al-arcade.com/api/manage/bots/yasmin \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# Bulk create
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/bots/bulk \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '[{"id":"bot1","name":"Bot One","style":"test","skill_level":5,"depth":5},{"id":"bot2","name":"Bot Two","style":"test","skill_level":10,"depth":10}]' | jq .

# Bulk delete
curl -s -X DELETE https://stockfishapi.caprover.al-arcade.com/api/manage/bots/bulk \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"ids":["bot1","bot2"]}' | jq .

# Export all bots (download)
curl -s https://stockfishapi.caprover.al-arcade.com/api/manage/bots/export \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" -o bots_backup.json

# Import bots (with overwrite)
curl -s -X POST "https://stockfishapi.caprover.al-arcade.com/api/manage/bots/import?overwrite=true" \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d @bots_backup.json | jq .

# Upload portrait
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/bots/amina/portrait \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -F "portrait=@amina.png" | jq .

# Delete portrait
curl -s -X DELETE https://stockfishapi.caprover.al-arcade.com/api/manage/bots/amina/portrait \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# Pool stats
curl -s https://stockfishapi.caprover.al-arcade.com/api/manage/pool \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# Test move (bot mode)
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/test-move \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1","bot_id":"grandmaster"}' | jq .

# Test move (raw mode - custom engine params)
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/test-move \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1","raw_mode":true,"depth":30,"skill_level":20,"contempt":0}' | jq .

# Deep analysis
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/manage/analyze \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1","depth":30,"lines":5}' | jq .

# Get settings
curl -s https://stockfishapi.caprover.al-arcade.com/api/manage/settings \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .

# Update settings
curl -s -X PATCH https://stockfishapi.caprover.al-arcade.com/api/manage/settings \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" \
  -H "Content-Type: application/json" \
  -d '{"pool_size":16,"idle_timeout_sec":600}' | jq .

# View logs
curl -s "https://stockfishapi.caprover.al-arcade.com/api/manage/logs?limit=20" \
  -H "X-API-Key: sk-alarc-stockfish-mgmt-2024" | jq .


================================================================================
ADMIN PANEL
================================================================================

URL: https://stockfishapi.caprover.al-arcade.com/admin
Login: username "admin", password "Alarcade123#"

Features:
  - Dashboard: live pool stats, bot count, request metrics
  - Bot management: create, edit, delete bots at runtime
  - Pool monitoring: alive/idle process counts
  - Test Move: test any bot with a custom FEN position
  - Request Logs: last 100 requests with method, path, status, duration, IP
  - Settings: view/modify port, pool size, idle timeout

Note: Runtime changes (bot edits, new bots) persist only until container restart.
      Core bot definitions are compiled into the binary.


================================================================================
INFRASTRUCTURE
================================================================================

  - Engine: Stockfish 18 (compiled from source, NNUE enabled)
  - Runtime: Go 1.22, single static binary
  - Process Pool: 12 Stockfish processes (configurable via POOL_SIZE env)
  - Pre-warmed: half the pool at startup for instant first requests
  - Idle Reaper: kills processes unused for 300s (configurable via IDLE_TIMEOUT_SEC)
  - Platform: Docker on CapRover (Ubuntu 22.04 base)
  - Architecture: x86-64-sse41-popcnt (broad server CPU compatibility)
  - Health Check: every 30s, 10s timeout, 3 retries, 15s start period
  - Port: 80 inside container (CapRover handles HTTPS/reverse proxy)


================================================================================
ENVIRONMENT VARIABLES
================================================================================

  PORT=80                              # HTTP listen port
  STOCKFISH_PATH=/usr/local/bin/stockfish  # path to Stockfish binary
  POOL_SIZE=12                         # max concurrent Stockfish processes
  IDLE_TIMEOUT_SEC=300                 # kill idle processes after this many seconds


================================================================================
INTEGRATION EXAMPLES
================================================================================

--- JavaScript/Fetch ---

// Get a move from "nour" bot
const response = await fetch('https://stockfishapi.caprover.al-arcade.com/api/chess/move', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    fen: 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1',
    bot_id: 'nour'
  })
});
const data = await response.json();
console.log(data.best_move); // e.g. "e7e5"

// Analyze a position
const analysis = await fetch('https://stockfishapi.caprover.al-arcade.com/api/chess/analyze', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    fen: 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1',
    depth: 20,
    lines: 3
  })
});
const result = await analysis.json();
result.lines.forEach(line => {
  console.log(`#${line.rank}: ${line.move} (eval: ${line.evaluation})`);
});

// List all bots
const botsResp = await fetch('https://stockfishapi.caprover.al-arcade.com/api/chess/bots');
const botsData = await botsResp.json();
botsData.bots.forEach(bot => {
  console.log(`${bot.name} (${bot.elo_min}-${bot.elo_max} ELO) - ${bot.style}`);
});


--- Python ---

import requests

# Get move
resp = requests.post('https://stockfishapi.caprover.al-arcade.com/api/chess/move', json={
    'fen': 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1',
    'bot_id': 'omar'
})
move = resp.json()
print(f"Best move: {move['best_move']}, Eval: {move['evaluation']}")

# Analyze
resp = requests.post('https://stockfishapi.caprover.al-arcade.com/api/chess/analyze', json={
    'fen': 'r1bqkbnr/pppppppp/2n5/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 1 2',
    'depth': 22,
    'lines': 5
})
for line in resp.json()['lines']:
    print(f"#{line['rank']}: {line['move']} (eval {line['evaluation']:.2f})")


--- cURL ---

# Quick move
curl -s -X POST https://stockfishapi.caprover.al-arcade.com/api/chess/move \
  -H "Content-Type: application/json" \
  -d '{"fen":"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1","bot_id":"amina"}' | jq .

# Health check
curl -s https://stockfishapi.caprover.al-arcade.com/health | jq .


================================================================================
TYPICAL GAME FLOW (for client integration)
================================================================================

1. GET /api/chess/bots -> show bot selection to user
2. User picks a bot (e.g. "nour") and starts a game
3. Client tracks FEN locally (or uses a chess library)
4. When it's the bot's turn:
   POST /api/chess/move with current FEN and bot_id
5. Apply the returned best_move to the board
6. Repeat from step 4 until checkmate/stalemate/draw
7. Optionally: POST /api/chess/analyze for post-game analysis

Important notes for client implementation:
  - Always send the FULL FEN including castling rights, en passant, move counters
  - The API does NOT validate if the FEN is a legal position
  - The API does NOT track game state - it's stateless (one move per request)
  - Handle the artificial think_time_ms for UX (show "thinking..." animation)
  - Handle 429 rate limit gracefully (retry after 1 second)
  - The response time can be up to 8000ms+ for grandmaster bot (due to simulated think time)


================================================================================
ERROR HANDLING
================================================================================

All errors return JSON with an "error" field:

  400 Bad Request         - malformed JSON, missing required fields
  404 Not Found           - invalid bot_id
  429 Too Many Requests   - rate limit exceeded (60/min/IP)
  500 Internal Server Error - Stockfish process crash, pool exhaustion, timeout
  503 Service Unavailable - health check failed (engine not responding)

Recommended retry strategy:
  - 429: wait 1-2 seconds, retry
  - 500: wait 2-5 seconds, retry up to 3 times
  - 503: service is down, alert user


================================================================================
RESPONSE TIME EXPECTATIONS
================================================================================

Bot             | Typical Response Time (includes simulated think time)
----------------|------------------------------------------------------
amina           | 500ms - 2000ms
tarek           | 1000ms - 3000ms
nour            | 800ms - 3000ms
omar            | 1500ms - 4000ms
layla           | 1000ms - 5000ms
ziad            | 2000ms - 6000ms
grandmaster     | 3000ms - 8000ms

Analysis endpoint: 1-30 seconds depending on depth (no artificial delay).
Health check: < 5 seconds.

Set client timeouts accordingly (recommend 15s for moves, 35s for analysis).
